package com.hotel.tv.services.impl;

import com.autumn.exception.ExceptionUtils;
import com.autumn.mybatis.wrapper.EntityQueryWrapper;
import com.autumn.mybatis.wrapper.QueryWrapper;
import com.autumn.security.token.CredentialsDeviceInfo;
import com.autumn.util.AutoMapUtils;
import com.autumn.util.StringUtils;
import com.autumn.zero.authorization.entities.common.AbstractRole;
import com.autumn.zero.authorization.entities.common.AbstractUser;
import com.autumn.zero.authorization.entities.common.UserRole;
import com.autumn.zero.authorization.services.UserRoleDefinition;
import com.autumn.zero.authorization.services.impl.AbstractAuthorizationService;
import com.hotel.tv.entities.auth.HotelRole;
import com.hotel.tv.entities.auth.HotelUser;
import com.hotel.tv.entities.auth.query.HotelRoleByUserQuery;
import com.hotel.tv.entities.auth.query.HotelUserByRoleQuery;
import com.hotel.tv.repositories.auth.HotelRoleRepository;
import com.hotel.tv.repositories.auth.HotelUserRepository;
import com.hotel.tv.repositories.auth.query.HotelRoleByUserQueryRepository;
import com.hotel.tv.repositories.auth.query.HotelUserByRoleQueryRepository;
import com.hotel.tv.services.DeviceTypeConstants;
import com.hotel.tv.services.HotelAuthorizationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * </p>
 *
 * @description TODO
 * @author: 老码农
 * @create: 2020-04-10 10:45
 **/
@Service
@Primary
public class HotelAuthorizationServiceImpl extends
        AbstractAuthorizationService<HotelUser, HotelUserRepository, HotelRole, HotelRoleRepository>
        implements HotelAuthorizationService {

    /**
     * 实例化 AbstractUserService 类
     */
    public HotelAuthorizationServiceImpl() {
        super(HotelUser.class, HotelRole.class);
    }

    @Autowired
    private HotelUserRepository userRepository;

    @Autowired
    private HotelRoleRepository roleRepository;

    @Autowired
    private HotelUserByRoleQueryRepository roleQueryRepository;

    @Autowired
    private HotelRoleByUserQueryRepository roleUserQueryRepository;

    @Override
    protected HotelUserRepository getUserRepository() {
        return this.userRepository;
    }

    @Override
    protected HotelRoleRepository getRoleRepository() {
        return this.roleRepository;
    }

    @Override
    public List<HotelRole> queryUserByRoles(long userId) {
        QueryWrapper query = new QueryWrapper(HotelRoleByUserQuery.class);
        query.where().eq(HotelRoleByUserQuery.FIELD_USER_ID, userId)
                .of().orderBy(HotelRoleByUserQuery.FIELD_SORT_ID)
                .orderBy(HotelRoleByUserQuery.FIELD_ID);
        List<HotelRoleByUserQuery> queryRoles = roleUserQueryRepository.selectForList(query);
        return AutoMapUtils.mapForList(queryRoles, HotelRole.class);
    }

    @Override
    public List<HotelUser> queryRoleByUsers(long roleId) {
        QueryWrapper query = new QueryWrapper(HotelUserByRoleQuery.class);
        query.where().eq(HotelUserByRoleQuery.FIELD_ROLE_ID, roleId)
                .of().orderBy(HotelUserByRoleQuery.FIELD_ID);
        List<HotelUserByRoleQuery> queryUsers = roleQueryRepository.selectForList(query);
        return AutoMapUtils.mapForList(queryUsers, HotelUser.class);
    }

    @Override
    public UserRoleDefinition<HotelUser, HotelRole> createAdministratorDefinition() {
        return new HotelAdministratorDefinition();
    }

    @Override
    protected void checkRoleEdit(HotelRole role, boolean checkName) {
        if (role.getUsers() == null) {
            role.setUsers(new ArrayList<>());
        }
        EntityQueryWrapper<HotelRole> userQuery = new EntityQueryWrapper<>(this.getRoleEntityClass());
        if (checkName) {
            userQuery.reset();
            userQuery.where().eq(AbstractRole.FIELD_NAME, role.getName());
            if (role.getOrganizeId() != null) {
                userQuery.lambda().where().eq(HotelRole::getOrganizeId, role.getOrganizeId());
            }
            if (userQuery.countByWhere(this.getRoleRepository()) > 0) {
                ExceptionUtils.throwValidationException("角色名称 " + role.getName() + " 已存在。");
            }
        }
        HotelUserRepository userRepository = this.getUserRepository();
        int row = 1;
        for (UserRole user : role.getUsers()) {
            EntityQueryWrapper<HotelUser> query = new EntityQueryWrapper(this.getUserEntityClass());
            query.where().eq(AbstractUser.FIELD_ID, user.getUserId());
            if (role.getOrganizeId() != null) {
                query.lambda().where().eq(HotelUser::getOrganizeId, role.getOrganizeId());
            }
            if (userRepository.countByWhere(query) == 0) {
                ExceptionUtils.throwValidationException("第" + row + "行的用户不存在。");
            }
            row++;
        }
    }

    @Override
    protected void checkUserEdit(HotelUser user, boolean checkUserName, boolean checkPhoneNumber, boolean checkEmailAddress) {
        if (user.getRoles() == null) {
            user.setRoles(new ArrayList<>());
        }
        EntityQueryWrapper<HotelUser> userQuery = new EntityQueryWrapper<>(this.getUserEntityClass());
        if (checkUserName) {
            userQuery.reset();
            userQuery.where().eq(AbstractUser.FIELD_USER_NAME, user.getUserName());
            if (userQuery.countByWhere(this.getUserRepository()) > 0) {
                ExceptionUtils.throwValidationException("用户名称 " + user.getUserName() + " 已存在。");
            }
        }
        if (checkPhoneNumber && !StringUtils.isNullOrBlank(user.getPhoneNumber())) {
            userQuery.reset();
            userQuery.where().eq(AbstractUser.FIELD_PHONE_NUMBER, user.getPhoneNumber().trim());
            if (userQuery.countByWhere(this.getUserRepository()) > 0) {
                ExceptionUtils.throwValidationException("手机号 " + user.getPhoneNumber() + " 已存在或已注册过。");
            }
        }
        if (checkEmailAddress && !StringUtils.isNullOrBlank(user.getEmailAddress())) {
            userQuery.reset();
            userQuery.where().eq(AbstractUser.FIELD_EMAIL_ADDRESS, user.getEmailAddress().trim());
            if (userQuery.countByWhere(this.getUserRepository()) > 0) {
                ExceptionUtils.throwValidationException("邮箱 " + user.getEmailAddress() + " 已存在或已注册过。");
            }
        }
        HotelRoleRepository roleRepository = this.getRoleRepository();
        int row = 1;
        for (UserRole role : user.getRoles()) {
            EntityQueryWrapper<HotelRole> query = new EntityQueryWrapper(this.getRoleEntityClass());
            query.where().eq(AbstractRole.FIELD_ID, role.getRoleId());
            if (user.getOrganizeId() != null) {
                query.lambda().where().eq(HotelRole::getOrganizeId, user.getOrganizeId());
            }
            if (roleRepository.countByWhere(query) == 0) {
                ExceptionUtils.throwValidationException("第" + row + "行的角色不存在。");
            }
            row++;
        }
    }

    @Override
    public void saveCheckCredentialsDeviceInfo(CredentialsDeviceInfo credentialsDeviceInfo) {
        super.saveCheckCredentialsDeviceInfo(credentialsDeviceInfo);
        if (!DeviceTypeConstants.exist(credentialsDeviceInfo.getDeviceType())) {
            throw ExceptionUtils.throwValidationException("设备类型[" + credentialsDeviceInfo.getDeviceType() + "]不支持。");
        }
    }
}
